package com.es.gateway.sdk.util;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequenceGenerator;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jce.ECPointUtil;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.KeyAgreement;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.*;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
import java.util.ArrayList;

@Slf4j
public class ECCUtil {
    public static final String DEFAULT_CURVE_NAME = "secp256r1";
    public static final String SIGNATURE_ALGORITM = "NONEwithECDSA";
    public static final String KEY_ALGORITHM = "EC";

    /**
     * 生成密钥对
     * @return ecc 密钥对
     */
    public static KeyPair genKeyPair() {
        KeyPair keyPair = null;
        try {
            Security.addProvider(new BouncyCastleProvider());
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC","BC");
            ECGenParameterSpec spec = new ECGenParameterSpec(DEFAULT_CURVE_NAME);
            kpg.initialize(spec);
            keyPair = kpg.generateKeyPair();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        } finally {
            return keyPair;
        }
    }

    /**
     * 获取私钥DER格式字符串
     * @param keyPair
     * @return
     */
    public static String getPrivateKey(KeyPair keyPair) {
        PrivateKey privateKey = keyPair.getPrivate();
        byte[] privateKeyBytes = privateKey.getEncoded();
        String privateKeyBase64 = B64Util.encodeStr(privateKeyBytes);

        return privateKeyBase64;
    }

    /**
     * 获取公钥DER格式字符串
     * @param keyPair
     * @return
     */
    public static String getPublickey(KeyPair keyPair) {
        PublicKey publicKey = keyPair.getPublic();
        byte[] publicKeyBytes = publicKey.getEncoded();
        String publicKeyBase64 = B64Util.encodeStr(publicKeyBytes);

        return publicKeyBase64;
    }

    /**
     * 序列化为公钥对象
     * @param pubKeyBytes der格式公钥
     * @return
     */
    public static ECPublicKey getPublickey(byte[] pubKeyBytes) {
        ECPublicKey ecPublicKey = null;
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKeyBytes);
        try {
            Security.addProvider(new BouncyCastleProvider());
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            ecPublicKey = (ECPublicKey) keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return ecPublicKey;
        }
    }

    /**
     * 对摘要进行签名
     * @param hash 摘要数据
     * @param privateKeyStr 私钥字符串
     * @return 签名数据
     */
    public static byte[] sign(byte[] hash, String privateKeyStr) {
        byte[] signatureBuff = null;
        byte[] privateKeyBuff = B64Util.decode(privateKeyStr);
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyBuff);

        try {
            Security.addProvider(new BouncyCastleProvider());
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITM);
            signature.initSign(privateKey);
            signature.update(hash);
            signatureBuff = signature.sign();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            return signatureBuff;
        }
    }

    /**
     * 验签
     * @param signatureBuff 签名摘要
     * @param hashBuff 数据摘要
     * @param publicKeyBase64 公钥数据
     * @return 验签结果
     */
    public static boolean verify(byte[] signatureBuff, byte[] hashBuff, String publicKeyBase64) {
        boolean verifyResult = false;
        byte[] publicKeyBuff = B64Util.decode(publicKeyBase64);

        Security.addProvider(new BouncyCastleProvider());
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyBuff);
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Signature signature = Signature.getInstance(SIGNATURE_ALGORITM);
            signature.initVerify(publicKey);
            signature.update(hashBuff);
            verifyResult = signature.verify(signatureBuff);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } finally {
            return verifyResult;
        }
    }
}
